home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
TECHNICA
/
COMPUTER
/
H254.ZIP
/
IRITSM3S.ZIP
/
IRITFLTR
/
IRIT2RAY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-26
|
24KB
|
791 lines
/*****************************************************************************
* Filter to convert IRIT data files to ray shade format. *
* *
* Written by: Gershon Elber Ver 1.0, Sep 1991 *
*****************************************************************************/
#ifdef __MSDOS__
#include <dos.h>
#include <alloc.h>
#endif /* __MSDOS__ */
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include "irit_sm.h"
#include "iritprsr.h"
#include "getarg.h"
#include "genmat.h"
#define DIST_EPSILON 2e-4
#define SIZE_EPSILON 1e-5
#define CONVEX_EPSILON 1e-3
#ifdef __MSDOS__
extern unsigned int _stklen = 32766; /* Increase default stack size. */
#endif /* __MSDOS__ */
#ifdef NO_CONCAT_STR
static char *VersionStr =
"Irit2Ray Version 3.0, Gershon Elber,\n\
(C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
#else
static char *VersionStr = "Irit2Ray " VERSION ", Gershon Elber, "
__DATE__ ", " __TIME__ "\n"
"(C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
#endif /* NO_CONCAT_STR */
static char
*CtrlStr = "irit2ray l%- 4%- G%-GridSize!d f%-FineNess!d o%-OutName!s g%- z%- DFiles!*s";
static char
*OutFileName = "irit2ray";
static int
GlblGridSize = 5,
GlblGridFlag = FALSE,
GlblFineNess = 5,
GlblDumpOnlyGeometry = FALSE,
FourPerFlat = FALSE;
static MatrixType CrntViewMat; /* This is the current view! */
static int TransColorTable[][4] = {
{ /* BLACK */ 0, 0, 0, 0 },
{ /* BLUE */ 1, 0, 0, 255 },
{ /* GREEN */ 2, 0, 255, 0 },
{ /* CYAN */ 3, 0, 255, 255 },
{ /* RED */ 4, 255, 0, 0 },
{ /* MAGENTA */ 5, 255, 0, 255 },
{ /* BROWN */ 6, 50, 0, 0 },
{ /* LIGHTGRAY */ 7, 127, 127, 127 },
{ /* DARKGRAY */ 8, 63, 63, 63 },
{ /* LIGHTBLUE */ 9, 0, 0, 255 },
{ /* LIGHTGREEN */ 10, 0, 255, 0 },
{ /* LIGHTCYAN */ 11, 0, 255, 255 },
{ /* LIGHTRED */ 12, 255, 0, 0 },
{ /* LIGHTMAGENTA */ 13, 255, 0, 255 },
{ /* YELLOW */ 14, 255, 255, 0 },
{ /* WHITE */ 15, 255, 255, 255 },
{ /* BROWN */ 20, 50, 0, 0 },
{ /* DARKGRAY */ 56, 63, 63, 63 },
{ /* LIGHTBLUE */ 57, 0, 0, 255 },
{ /* LIGHTGREEN */ 58, 0, 255, 0 },
{ /* LIGHTCYAN */ 59, 0, 255, 255 },
{ /* LIGHTRED */ 60, 255, 0, 0 },
{ /* LIGHTMAGENTA */ 61, 255, 0, 255 },
{ /* YELLOW */ 62, 255, 255, 0 },
{ /* WHITE */ 63, 255, 255, 255 },
{ -1, 0, 0, 0 }
};
static IPObjectStruct *MainGetDataFiles(char **DataFileNames,
int NumOfDataFiles);
static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf, int FourPerFlat,
int FineNess);
static void DumpDataForRayShade(IPObjectStruct *PObjects);
static int DumpOneObject(FILE *FRay, FILE *FGeom, IPObjectStruct *PObject);
static int DumpOnePolygon(FILE *f, IPPolygonStruct *PPolygon);
static int IsConvexPolygon(IPPolygonStruct *Pl);
static RealType *MapPoint(RealType *Pt);
static RealType *MapVector(RealType *Pt, RealType *Vec);
static void MyExit(int ExitCode);
/*****************************************************************************
* Main routine - Read Parameter line and do what you need... *
*****************************************************************************/
void main(int argc, char **argv)
{
int Error,
FineNessFlag = FALSE,
LinearOnePolyFlag = FALSE,
VerFlag = FALSE,
OutFileFlag = FALSE,
NumFiles = 0;
char Line[LINE_LEN_LONG], *p,
**FileNames = NULL;
IPObjectStruct *PObjects;
#ifdef __MSDOS__
ctrlbrk((int (*)()) MyExit); /* Kill process if ^C. */
#endif /* __MSDOS__ */
if ((Error = GAGetArgs (argc, argv, CtrlStr, &LinearOnePolyFlag,
&FourPerFlat, &GlblGridFlag, &GlblGridSize,
&FineNessFlag, &GlblFineNess, &OutFileFlag,
&OutFileName, &GlblDumpOnlyGeometry,
&VerFlag, &NumFiles, &FileNames)) != 0) {
GAPrintErrMsg(Error);
GAPrintHowTo(CtrlStr);
MyExit(1);
}
if (VerFlag) {
fprintf(stderr, "\n%s\n\n", VersionStr);
GAPrintHowTo(CtrlStr);
MyExit(0);
}
if (LinearOnePolyFlag) {
fprintf(stderr, "Linear patch side will have a single polygon.\n");
CagdSetLinear2Poly(CAGD_ONE_POLY_PER_COLIN);
}
else
CagdSetLinear2Poly(CAGD_REG_POLY_PER_LIN);
fprintf(stderr, "%s triangles per flat will be created.\n",
FourPerFlat ? "Four" : "Two");
if (!NumFiles) {
fprintf(stderr, "No data file names where given, exit.\n");
GAPrintHowTo(CtrlStr);
MyExit(1);
}
if (!OutFileFlag) { /* Pick the first input name as output name. */
strcpy(Line, FileNames[0]);
if ((p = strrchr(Line, '.')) != NULL); /* Remove old file type. */
*p = 0;
OutFileName = malloc(strlen(Line) + 1);
strcpy(OutFileName, Line);
}
/* Get the data files: */
IritPrsrPolyListCirc = FALSE;
PObjects = MainGetDataFiles(FileNames, NumFiles);
if (IritPrsrWasPrspMat)
MultTwo4by4(CrntViewMat, IritPrsrViewMat, IritPrsrPrspMat);
else
GEN_COPY(CrntViewMat, IritPrsrViewMat, sizeof(MatrixType));
DumpDataForRayShade(PObjects);
MyExit(0);
}
/*****************************************************************************
* Main routine to read the data description files: *
* Returns pointer to pointers on FileDescription structures (one per file). *
*****************************************************************************/
static IPObjectStruct *MainGetDataFiles(char **DataFileNames,
int NumOfDataFiles)
{
int i;
FILE *f;
char
*ErrorMsg = NULL;
IPObjectStruct *PObj, *PObjTail,
*PObjHead = NULL;
for (i = 0; i < NumOfDataFiles; i++) {
#ifdef __MSDOS__
if ((f = fopen(*DataFileNames, "rt")) == NULL) { /* Open the file. */
#else
if ((f = fopen(*DataFileNames, "r")) == NULL) { /* Open the file. */
#endif /* __MSDOS__ */
fprintf(stderr, "Can't open data file %s\n", *DataFileNames);
MyExit(1);
}
if ((PObj = IritPrsrGetObjects(f)) != NULL) { /* Get the data file. */
PObjTail = PObj;
while (PObjTail -> Pnext) PObjTail = PObjTail -> Pnext;
PObjTail -> Pnext = PObjHead;
PObjHead = PObj;
}
fclose(f); /* Close the file. */
if (IritPrsrParseError(&ErrorMsg)) {
fprintf(stderr, "Parse error in \"%s\":\n%s\n", *DataFileNames, ErrorMsg);
MyExit(1);
}
DataFileNames++; /* Skip to next file name. */
}
if (PObjHead == NULL) {
fprintf(stderr, "No data found.\n");
MyExit(1);
}
return PObjHead;
}
/*****************************************************************************
* Routine to convert all surfaces/curves into polylines as follows: *
* Curves are converted to single polyline with SamplesPerCurve samples. *
* Surface are converted into GlblNumOfIsolines curves in each axes, each *
* handled as Curves above. The curves and surfaces are then deleted. *
*****************************************************************************/
IPObjectStruct *IritPrsrProcessFreeForm(IPObjectStruct *CrvObjs,
IPObjectStruct *SrfObjs)
{
int LocalFourPerFlat;
float RelativeFineNess;
CagdCrvStruct *Crvs;
CagdSrfStruct *Srf, *Srfs;
IPObjectStruct *PObj, *PObjNext;
IPPolygonStruct *PPolygon, *PPolygonTemp;
if (CrvObjs == NULL && SrfObjs == NULL) return NULL;
/* Make sure requested format is something reasonable. */
if (GlblFineNess < 2) {
GlblFineNess = 2;
fprintf(stderr, "FineNess is less than 2, 2 picked instead.\n");
}
if (CrvObjs) {
/* Curves are not rendered at this time and they are ignored. */
for (PObj = CrvObjs; PObj != NULL;) {
Crvs = PObj -> U.PCrvs;
CagdCrvFreeList(Crvs);
PObjNext = PObj -> Pnext;
free((VoidPtr) PObj);
PObj = PObjNext;
}
CrvObjs = NULL;
}
if (SrfObjs) {
for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
CagdBBoxStruct BBox, TempBBox;
char GridStr[LINE_LEN], *p;
Srfs = PObj -> U.PSrfs;
PObj -> U.PPolygon = NULL;
RelativeFineNess = 1.0;
LocalFourPerFlat = FourPerFlat;
if (IritPrsrGetStrAttrib(PObj, "twoperflat"))
LocalFourPerFlat = FALSE;
if (IritPrsrGetStrAttrib(PObj, "fourperflat"))
LocalFourPerFlat = TRUE;
if ((p = IritPrsrGetStrAttrib(PObj, "resolution")) != NULL &&
sscanf(p, "%f", &RelativeFineNess) != 1)
RelativeFineNess = 1.0;
for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
if (GlblGridFlag) {
/* Generate bounding box to the surfaces and estimate */
/* the grid size for it using GlblGridSize. */
if (Srf == Srfs)
CagdSrfBBox(Srf, &BBox);
else {
CagdSrfBBox(Srf, &TempBBox);
CagdMergeBBox(&BBox, &TempBBox);
}
}
PPolygon = PPolygonTemp =
Surface2Polygons(Srf, LocalFourPerFlat,
(int) (RelativeFineNess * GlblFineNess));
while (PPolygonTemp -> Pnext)
PPolygonTemp = PPolygonTemp -> Pnext;
PPolygonTemp -> Pnext = PObj -> U.PPolygon;
PObj -> U.PPolygon = PPolygon;
}
CagdSrfFreeList(Srfs);
if (GlblGridFlag) {
RealType
Dx = BBox.Max[0] - BBox.Min[0],
Dy = BBox.Max[1] - BBox.Min[1],
Dz = BBox.Max[2] - BBox.Min[2],
M = MAX(MAX(Dx, Dy), Dz);
int IDx = (int) (GlblGridSize * (Dx / M)),
IDy = (int) (GlblGridSize * (Dy / M)),
IDz = (int) (GlblGridSize * (Dz / M));
/* Save grid information derived from the surface bbox. */
sprintf(GridStr, "%d %d %d",
IDx > 0 ? IDx : 1,
IDy > 0 ? IDy : 1,
IDz > 0 ? IDz : 1);
IritPrsrSetStrAttrib(PObj, "GridSize", GridStr);
}
}
}
return SrfObjs;
}
/*****************************************************************************
* Routine to convert a single surface into a polylines with SamplesPerCurve *
* samples, NumOfIsolines isolines into a polyline object list. *
*****************************************************************************/
static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf, int FourPerFlat,
int FineNess)
{
int i, j;
IPVertexStruct *V, *VHead,
*VTail = NULL;
IPPolygonStruct *P,
*PHead = NULL;
CagdPolygonStruct *CagdPolygon,
*CagdPolygonHead = CagdSrf2Polygons(Srf, FineNess, TRUE, FourPerFlat);
for (CagdPolygon = CagdPolygonHead, VHead = NULL;
CagdPolygon != NULL;
CagdPolygon = CagdPolygon -> Pnext) {
/* All polygons are triangles! */
for (i = 0, VHead = NULL; i < 3; i++) { /* Convert to vertices. */
V = IritPrsrNewVertexStruct();
IP_SET_VRTX_NORMAL(V); /* This vertex has normal. */
for (j = 0; j < 3; j++) /* Convert to our format. */
V -> Coord[j] = CagdPolygon -> Polygon[i].Pt[j];
for (j = 0; j < 3; j++)
V -> Normal[j] = CagdPolygon -> Normal[i].Vec[j];
if (VHead) {
VTail -> Pnext = V;
VTail = V;
}
else
VHead = VTail = V;
}
P = IritPrsrNewPolygonStruct();
P -> PVertex = VHead;
P -> Type = IP_POLYGON;
P -> Pnext = PHead;
PHead = P;
}
CagdPolygonFreeList(CagdPolygonHead);
return PHead;
}
/*****************************************************************************
* Dumps the data for ray shade into stdout. *
*****************************************************************************/
static void DumpDataForRayShade(IPObjectStruct *PObjects)
{
static char *Header1[] = {
"/*",
" * This file was automatically created from IRIT solid modeller data",
" * using Irit2ray - IRIT to RayShade filter.",
" *",
" * (c) Copyright 1991/92 Gershon Elber, Non commercial use only.",
" */",
"",
NULL
};
static char *Header2[] = {
"",
"eyep 0 0 10",
"lookp 0 0 0",
"up 0 1 0",
"fov 12",
"",
"light 1 1 1 point 10 30 10",
"",
NULL
};
int i,
TotalPolys = 0;
char Line[128];
IPObjectStruct *PObj,
*PObjHead = NULL;
FILE *FGeom, *FRay;
sprintf(Line, "%s.ray", OutFileName);
if (!GlblDumpOnlyGeometry) {
if ((FRay = fopen(Line, "w")) == NULL) {
fprintf(stderr, "Failed to open \"%s\".\n", Line);
exit(2);
}
}
else
FRay = NULL;
sprintf(Line, "%s.geom", OutFileName);
if ((FGeom = fopen(Line, "w")) == NULL) {
fprintf(stderr, "Failed to open \"%s\".\n", Line);
exit(2);
}
if (FRay != NULL)
for (i = 0; Header1[i] != NULL; i++)
fprintf(FRay, "%s\n", Header1[i]);
for (i = 0; Header1[i] != NULL; i++)
fprintf(FGeom, "%s\n", Header1[i]);
/* Reverse object list since it was loaded in reverse by iritprsr module.*/
while (PObjects != NULL) {
PObj = PObjects;
PObjects = PObjects -> Pnext;
PObj -> Pnext = PObjHead;
PObjHead = PObj;
}
PObjects = PObjHead;
while (PObjects) {
TotalPolys += DumpOneObject(FRay, FGeom, PObjects);
PObjects = PObjects -> Pnext;
}
if (FRay != NULL) {
fprintf(FRay, "#include \"%s\"\n", Line);
for (i = 0; Header2[i] != NULL; i++)
fprintf(FRay, "%s\n", Header2[i]);
fclose(FRay);
}
fclose(FGeom);
fprintf(stderr, "\nTotal number of polygons - %d\n", TotalPolys);
}
/*****************************************************************************
* Routine to dump one object PObject. *
*****************************************************************************/
static int DumpOneObject(FILE *FRay, FILE *FGeom, IPObjectStruct *PObject)
{
static int
ObjectSeqNum = 1;
int i, j,
PolyCount = 0,
HasColor = FALSE,
HasSrfProp = FALSE;
char *p, Name[LINE_LEN], SrfPropString[LINE_LEN_LONG];
RealType RGBColor[3];
IPPolygonStruct
*PList = PObject -> U.PPolygon;
if (strlen(PObject -> Name) == 0)
sprintf(Name, "ObjSeq%d", ObjectSeqNum);
else
strcpy(Name, PObject -> Name);
SrfPropString[0] = 0;
for (i = 0; i < PObject -> Attrs.NumStrAttribs; i++)
{
if (strcmp(PObject -> Attrs.StrAttrName[i], "specpow") == 0 ||
strcmp(PObject -> Attrs.StrAttrName[i], "reflect") == 0 ||
strcmp(PObject -> Attrs.StrAttrName[i], "transp") == 0 ||
strcmp(PObject -> Attrs.StrAttrName[i], "body") == 0 ||
strcmp(PObject -> Attrs.StrAttrName[i], "index") == 0) {
strcat(SrfPropString, PObject -> Attrs.StrAttrName[i]);
strcat(SrfPropString, " ");
strcat(SrfPropString, PObject -> Attrs.StrAttrData[i]);
strcat(SrfPropString, " ");
HasSrfProp = TRUE;
}
}
if (GlblGridFlag) {
char *GridStr = IritPrsrGetStrAttrib(PObject, "GridSize");
if (GridStr != NULL)
fprintf(FGeom, "name %s grid %s\n", Name, GridStr);
else
fprintf(FGeom, "name %s list\n", Name);
}
else
fprintf(FGeom, "name %s list\n", Name);
while (PList) {
PolyCount += DumpOnePolygon(FGeom, PList);
PList = PList -> Pnext;
}
fprintf(FGeom, "end\n");
fprintf(stderr, "Processing \"%s\" - %d triangles.\n", Name, PolyCount);
if ((p = IritPrsrGetStrAttrib(PObject, "rgb")) != NULL)
{
# ifdef __MSDOS__
HasColor = sscanf(p, "%f,%f,%f",
# else
HasColor = sscanf(p, "%lf,%lf,%lf",
# endif /* __MSDOS__ */
&RGBColor[0], &RGBColor[1], &RGBColor[2]) == 3;
}
else if (IP_HAS_OBJ_RGB(PObject)) {
HasColor = TRUE;
for (i = 0; i < 3; i++) RGBColor[i] = PObject -> RGB[i];
}
else if (IP_HAS_OBJ_COLOR(PObject)) {
for (i = 0; TransColorTable[i][0] >= 0; i++) {
if (TransColorTable[i][0] == PObject -> Color) {
HasColor = TRUE;
for (j = 0; j < 3; j++) RGBColor[j] = TransColorTable[i][j+1];
break;
}
}
}
if (HasColor || HasSrfProp) {
if (FRay != NULL) {
fprintf(FRay, "surface %sSrfProp\n", Name);
if (HasColor) {
for (i = 0; i < 3; i++) RGBColor[i] /= 255.0;
fprintf(FRay, "\tambient %7.4lf %7.4lf %7.4lf\n",
0.1 * RGBColor[0],
0.1 * RGBColor[1],
0.1 * RGBColor[2]);
fprintf(FRay, "\tdiffuse %7.4lf %7.4lf %7.4lf\n",
0.7 * RGBColor[0],
0.7 * RGBColor[1],
0.7 * RGBColor[2]);
fprintf(FRay, "\tspecular %7.4lf %7.4lf %7.4lf\n",
0.8, 0.8, 0.8);
}
if (HasSrfProp)
fprintf(FRay, "\t%s\n", SrfPropString);
}
fprintf(FGeom, "object %sSrfProp %s", Name, Name);
}
else
fprintf(FGeom, "object %s", Name);
for (i = 0; i < PObject -> Attrs.NumStrAttribs; i++) {
if ((p = IritPrsrGetStrAttrib(PObject, "texture")) != NULL) {
if (FRay != NULL)
fprintf(FRay, "#define %sTEXTURE %s\n", Name, p);
fprintf(FGeom, " texture %sTEXTURE", Name);
break;
}
}
fprintf(FGeom, "\n\n");
if (FRay != NULL)
fprintf(FRay, "\n\n");
ObjectSeqNum++;
return PolyCount;
}
/*****************************************************************************
* Routine to dump one polygon, using global Matrix transform CrntViewMat. *
*****************************************************************************/
static int DumpOnePolygon(FILE *FGeom, IPPolygonStruct *PPolygon)
{
int i,
TriCount = 0;
RealType *MappedNormal[3], *MappedPoint[3], Normal[3], Vec1[3], Vec2[3];
IPVertexStruct *VFirst, *V1, *V2,
*VList = PPolygon -> PVertex;
if (VList == NULL) return 0;
if (!IsConvexPolygon(PPolygon)) {
static int Printed = FALSE;
if (!Printed) {
fprintf(stderr,
"Non convex polygon(s) may be in data (see CONVEX in IRIT).\n");
Printed = TRUE;
}
}
switch (PPolygon -> Type) {
case IP_POLYGON:
VFirst = VList;
V1 = VFirst -> Pnext;
V2 = V1 -> Pnext;
while (V2 != NULL) {
MappedPoint[0] = MapPoint(VFirst -> Coord);
MappedPoint[1] = MapPoint(V1 -> Coord);
MappedPoint[2] = MapPoint(V2 -> Coord);
/* Test for two type of degeneracies. Make sure that no two */
/* points in the triangle are the same and that they are */
/* not colinear. */
if (!PT_EQ(MappedPoint[0], MappedPoint[1]) &&
!PT_EQ(MappedPoint[0], MappedPoint[2]) &&
!PT_EQ(MappedPoint[1], MappedPoint[2])) {
PT_SUB(Vec1, MappedPoint[0], MappedPoint[1]);
PT_SUB(Vec2, MappedPoint[1], MappedPoint[2]);
PT_NORMALIZE(Vec1);
PT_NORMALIZE(Vec2);
CROSS_PROD(Normal, Vec1, Vec2);
if (PT_LENGTH(Normal) > SIZE_EPSILON) {
PT_NORMALIZE(Normal);
MappedNormal[0] =
MapVector(VFirst -> Coord, VFirst -> Normal);
MappedNormal[1] =
MapVector(V1 -> Coord, V1 -> Normal);
MappedNormal[2] =
MapVector(V2 -> Coord, V2 -> Normal);
if (DOT_PROD(Normal, MappedNormal[0]) < -SIZE_EPSILON ||
DOT_PROD(Normal, MappedNormal[1]) < -SIZE_EPSILON ||
DOT_PROD(Normal, MappedNormal[2]) < -SIZE_EPSILON) {
SWAP(RealType *, MappedPoint[1], MappedPoint[2]);
SWAP(RealType *, MappedNormal[1], MappedNormal[2]);
PT_SCALE(Normal, -1.0);
}
/* Make sure all normals are set properly: */
if (DOT_PROD(MappedNormal[0], MappedNormal[0]) < SIZE_EPSILON)
PT_COPY(MappedNormal[0], Normal);
if (DOT_PROD(MappedNormal[1], MappedNormal[1]) < SIZE_EPSILON)
PT_COPY(MappedNormal[1], Normal);
if (DOT_PROD(MappedNormal[2], MappedNormal[2]) < SIZE_EPSILON)
PT_COPY(MappedNormal[2], Normal);
TriCount++;
for (i = 0; i < 3; i++)
fprintf(FGeom,
"%s %10.7lf %10.7lf %10.7lf %9.6lf %9.6lf %9.6lf\n",
i == 0 ? " triangle" : "\t ",
MappedPoint[i][0],
MappedPoint[i][1],
MappedPoint[i][2],
MappedNormal[i][0],
MappedNormal[i][1],
MappedNormal[i][2]);
}
}
V1 = V2;
V2 = V2 -> Pnext;
}
break;
}
return TriCount;
}
/*****************************************************************************
* Routine to test if the given polygon is convex or not. *
* Algorithm: The polygon is convex iff the normals generated from cross *
* products of two consecutive edges points to the same direction. The same *
* direction is tested by a positive dot product. *
*****************************************************************************/
static int IsConvexPolygon(IPPolygonStruct *Pl)
{
RealType Size, V1[3], V2[3], LastNormal[3], Normal[3];
IPVertexStruct *VNext, *VNextNext,
*V = Pl -> PVertex;
LastNormal[0] = LastNormal[1] = LastNormal[2] = 0.0;
do {
if ((VNext = V -> Pnext) == NULL)
VNext = Pl -> PVertex;
if ((VNextNext = VNext -> Pnext) == NULL)
VNextNext = Pl -> PVertex;
PT_SUB(V1, VNext -> Coord, V -> Coord);
if ((Size = PT_LENGTH(V1)) > EPSILON) {
Size = 1.0 / Size;
PT_SCALE(V1, Size);
}
PT_SUB(V2, VNextNext -> Coord, VNext -> Coord);
if ((Size = PT_LENGTH(V2)) > EPSILON) {
Size = 1.0 / Size;
PT_SCALE(V2, Size);
}
CROSS_PROD(Normal, V1, V2);
if (V != Pl -> PVertex) {
if (PT_LENGTH(Normal) > CONVEX_EPSILON &&
DOT_PROD(Normal, LastNormal) < -CONVEX_EPSILON)
return FALSE;
}
PT_COPY(LastNormal, Normal);
V = VNext;
}
while (V != Pl -> PVertex && V != NULL);
return TRUE;
}
/*****************************************************************************
* Maps the given E3 point using the CrntViewMat. *
*****************************************************************************/
static RealType *MapPoint(RealType *Pt)
{
static int Count = 0;
static RealType MappedPts[3][3];
RealType *MappedPt = MappedPts[Count++];
if (Count >= 3) Count = 0;
MultVecby4by4(MappedPt, Pt, CrntViewMat);
return MappedPt;
}
/*****************************************************************************
* Maps the given E3 vector using the CrntViewMat. *
* This routine will return a zero vector if normal is not computable. *
*****************************************************************************/
static RealType *MapVector(RealType *Pt, RealType *Vec)
{
static int
Count = 0,
WasWarning = 0;
static RealType MappedVecs[3][3];
RealType MappedPt[3], Pt2[3], MappedPt2[3],
*MappedVec = MappedVecs[Count++];
if (Count >= 3) Count = 0;
if (DOT_PROD(Vec, Vec) < SIZE_EPSILON) {
MappedVec[0] = MappedVec[1] = MappedVec[2] = 0.0;
if (!WasWarning) {
WasWarning = 1;
fprintf(stderr, "Non computable normals detected. Approximated from geometry.\n");
}
}
else {
MultVecby4by4(MappedPt, Pt, CrntViewMat);
PT_ADD(Pt2, Pt, Vec);
MultVecby4by4(MappedPt2, Pt2, CrntViewMat);
PT_SUB(MappedVec, MappedPt2, MappedPt);
PT_NORMALIZE(MappedVec);
}
return MappedVec;
}
/*****************************************************************************
* Trap Cagd_lib errors right here. *
*****************************************************************************/
void CagdFatalError(CagdFatalErrorType ErrID)
{
char
*ErrorMsg = CagdDescribeError(ErrID);
fprintf(stderr, "CAGD_LIB: %s", ErrorMsg);
exit(-1);
}
/*****************************************************************************
* MyExit routine. Note it might call to CloseGraph without calling *
* InitGraph(), or call MouseClose() without MouseInit() etc. and it is the *
* responsibility of the individual modules to do nothing in these cases. *
*****************************************************************************/
static void MyExit(int ExitCode)
{
#ifdef __MSDOS__
fprintf(stderr,
"\nIrit2Ray: Core left %ldk.\n", coreleft() / 1024);
#endif /* __MSDOS__ */
exit(ExitCode);
}